package com.suyafei.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.suyafei.config.RabbitMQConfig;
import com.suyafei.enums.BizCodeEnum;
import com.suyafei.enums.CouponStateEnum;
import com.suyafei.enums.ProductOrderStateEnum;
import com.suyafei.enums.StockTaskStateEnum;
import com.suyafei.exception.BizException;
import com.suyafei.feign.ProductOrderFeignService;
import com.suyafei.interceptor.LoginIntercept;
import com.suyafei.mapper.CouponRecordMapper;
import com.suyafei.mapper.CouponTaskMapper;
import com.suyafei.model.CouponRecordDO;
import com.suyafei.model.CouponRecordMessage;
import com.suyafei.model.CouponTaskDO;
import com.suyafei.model.LoginUser;
import com.suyafei.request.LockCouponRecordRequest;
import com.suyafei.service.CouponRecordService;
import com.suyafei.util.JsonData;
import com.suyafei.vo.CouponRecordVO;
import com.suyafei.vo.CouponVO;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Propagation;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @program: suyafei-1024-shop
 * @description
 * @author: luffy
 * @create: 2021-03-07 20:14
 */
@Slf4j
@Service
public class CouponRecordServiceImpl implements CouponRecordService {


    @Autowired
    private ProductOrderFeignService orderFeignService;

    @Autowired
    private RabbitMQConfig rabbitMQConfig;

    @Autowired
    private RabbitTemplate rabbitTemplate;
    @Autowired
    private CouponRecordMapper couponRecordMapper;

    @Autowired
    private CouponTaskMapper couponTaskMapper;
    /**
     * 锁定优惠券
     *  1.锁定优惠卷记录
     *  2.task表插入记录
     *  3.发送延迟消息
     * @param recordRequest
     * @return
     */
    @Override
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    public JsonData lockCouponRecords(LockCouponRecordRequest recordRequest) {

        LoginUser loginUser = LoginIntercept.threadLocal.get();

        String orderOutTradeNo = recordRequest.getOrderOutTradeNo();
        List<Long> lockCouponRecordIds = recordRequest.getLockCouponRecordIds();

        int updateRows = couponRecordMapper.lockUseStateBatch(loginUser.getId(), CouponStateEnum.USED.name(), lockCouponRecordIds);

        List<CouponTaskDO> couponTaskDOList = lockCouponRecordIds.stream().map(obj -> {

            CouponTaskDO couponTaskDO = new CouponTaskDO();
            couponTaskDO.setCreateTime(new Date());
            couponTaskDO.setOutTradeNo(orderOutTradeNo);
            couponTaskDO.setCouponRecordId(obj);
            couponTaskDO.setLockState(StockTaskStateEnum.LOCK.name());
            return couponTaskDO;
        }).collect(Collectors.toList());

        int insertRows = couponTaskMapper.insertBatch(couponTaskDOList);
        log.info("优惠券记录锁定updateRows{}", updateRows);
        log.info("新增券记录task  insertRows{}", insertRows);

        if (lockCouponRecordIds.size() == insertRows && insertRows == updateRows) {
            //发送延迟消息 TODO

            for (CouponTaskDO couponTaskDO : couponTaskDOList) {
                CouponRecordMessage couponRecordMessage = new CouponRecordMessage();

                couponRecordMessage.setOutTradeNo(couponTaskDO.getOutTradeNo());
                couponRecordMessage.setTaskId(couponTaskDO.getId());
                rabbitTemplate.convertAndSend(rabbitMQConfig.getEventExchange(), rabbitMQConfig.getCouponReleaseDelayRoutingKey(), couponRecordMessage);

                log.info("延迟消息已发送{}",couponRecordMessage.toString());

            }
        }else {

            throw new BizException(BizCodeEnum.COUPON_RECORD_LOCK_FAIL);
        }

        return null;
    }

    /**
     * 解锁优惠券记录
     * 1.查询task工资单是否存在
     * 2.查询订单状态
     *
     * @param couponRecordMessage
     * @return
     */
    @Transactional(rollbackFor = Exception.class,propagation = Propagation.REQUIRED)
    @Override
    public boolean releaseCouponRecord(CouponRecordMessage couponRecordMessage) {
        //查询task是否存在
        CouponTaskDO couponTaskDO = couponTaskMapper.selectOne(new QueryWrapper<CouponTaskDO>().eq("id", couponRecordMessage.getTaskId()));
        if (couponTaskDO == null) {
            log.warn("工作单不存在，消息：{}", couponRecordMessage);
            return true;
        }
        if (couponTaskDO.getLockState().equalsIgnoreCase(StockTaskStateEnum.LOCK.name())) {

            //查询订单状态
            JsonData jsonData = orderFeignService.queryProductOrderState(couponRecordMessage.getOutTradeNo());
            if (jsonData.getCode() == 0) {
                //正常响应，判断状态
                String state = jsonData.getData().toString();
                if (ProductOrderStateEnum.NEW.name().equalsIgnoreCase(state)) {
                    //状态是new新建状态，则返回给消息队列，重新投递
                    log.warn("订单装填是new，返回给消息队列，重新投递:{}", couponRecordMessage);
                    return false;
                }
                if (ProductOrderStateEnum.PAY.name().equalsIgnoreCase(state)) {
                    //如果支付了，修改task状态为finish
                    couponTaskDO.setLockState(StockTaskStateEnum.FINISH.name());
                    couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", couponRecordMessage.getTaskId()));
                    log.info("订单已经支付，修改库存锁定工作单FINISH状态:{}", couponRecordMessage);
                    return true;
                }
            }

            //订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL，恢复优惠券使用记录为NEW
            log.warn("订单不存在，或者订单被取消，确认消息,修改task状态为CANCEL，恢复优惠券使用记录为NEW，message{}", couponRecordMessage);
            couponTaskDO.setLockState(StockTaskStateEnum.CANCEL.name());
            couponTaskMapper.update(couponTaskDO, new QueryWrapper<CouponTaskDO>().eq("id", couponRecordMessage.getTaskId()));
            couponRecordMapper.updateState(couponTaskDO.getCouponRecordId(), CouponStateEnum.NEW.name());
            //恢复优惠券为NEW
            couponRecordMapper.updateState(couponTaskDO.getCouponRecordId(), CouponStateEnum.NEW.name());
            return true;
        }else {
            log.warn("工作状态不是LOCK，state={}，消息体={}", couponTaskDO.getLockState(), couponRecordMessage);
            return true;
        }
    }

    @Override
    public CouponRecordVO findById(long recordId) {
        LoginUser loginUser = LoginIntercept.threadLocal.get();
        CouponRecordDO couponRecordDO = couponRecordMapper.selectOne(new QueryWrapper<CouponRecordDO>().eq("id", recordId).eq("user_id", loginUser.getId()));
        if (couponRecordDO == null) {
            return null;
        }
        CouponRecordVO couponRecordVO= beanProcess(couponRecordDO);
        return couponRecordVO;
    }

    /**
     * 分页查询领劵记录
     *
     * @param page
     * @param size
     * @return
     */
    @Override
    public Map<String, Object> page(int page, int size) {

        LoginUser loginUser = LoginIntercept.threadLocal.get();

        Page<CouponRecordDO> pageInfo = new Page<>(page, size);

        Page<CouponRecordDO> couponRecordDOPage = couponRecordMapper.selectPage(pageInfo, new QueryWrapper<CouponRecordDO>()
                .eq("user_id", loginUser.getId()).orderByDesc("create_time"));

        Map<String, Object> pageMap = new HashMap<>(3);

        pageMap.put("total_record", couponRecordDOPage.getTotal());
        pageMap.put("total_page", couponRecordDOPage.getPages());
        pageMap.put("current_data",couponRecordDOPage.getRecords().stream().map(obj->beanProcess(obj)).collect(Collectors.toList()));
        return pageMap;
    }

    /**
     * 转换bean
     * @param couponRecordDO
     * @return
     */
    private CouponRecordVO beanProcess(CouponRecordDO couponRecordDO) {

        CouponRecordVO couponRecordVO = new CouponRecordVO();
        BeanUtils.copyProperties(couponRecordDO, couponRecordVO);
        return couponRecordVO;
    }
}
